package org.lagou.router;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author junbao
 */
public class ReadyRestartInstances implements PathChildrenCacheListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(ReadyRestartInstances.class);

    private static final String LISTEN_PATHS = "/lagou/dubbo/restart/instances";

    private final CuratorFramework zkClient;

    // 当节点变化时赋值重启机器的信息列表
    private volatile Set<String> restartInstances = new HashSet<>();

    private ReadyRestartInstances(CuratorFramework zkClient) {
        this.zkClient = zkClient;
    }

    public static ReadyRestartInstances create() {
        final CuratorFramework zookeeperClient = ZookeeperClients.getClient();
        // 检查监听路径是否存在
        try {
            final Stat stat = zookeeperClient.checkExists().forPath(LISTEN_PATHS);
            // 如果监听路径不存在则创建
            if(stat == null) {
                zookeeperClient.create().creatingParentsIfNeeded().forPath(LISTEN_PATHS);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        final ReadyRestartInstances instances = new ReadyRestartInstances(zookeeperClient);
        // 创建一个NodeCache
        PathChildrenCache nodeCache = new PathChildrenCache(zookeeperClient, LISTEN_PATHS, false);
        // 给节店缓存对象加入监听
        nodeCache.getListenable().addListener(instances);
        try {
            nodeCache.start();
        } catch (Exception e) {
            LOGGER.error("启动路径监听失败");
            e.printStackTrace();
        }
        return instances;
    }


    /** 返回应用名和主机 拼接后的字符串*/
    private String buildApplicationAndInstancesString(String applicationName, String host) {
        return applicationName + "_" + host;
    }

    /** 增加重启实例的配置信息方法*/
    public void addRestartInstance(String applicationName, String host) throws Exception {
        zkClient.create().creatingParentsIfNeeded().forPath(LISTEN_PATHS + "/" + buildApplicationAndInstancesString(applicationName, host));
    }

    /** 删除重启实例的配置信息方法*/
    public void removeRestartInstance(String applicationName, String host) throws Exception {
        zkClient.delete().forPath(LISTEN_PATHS + "/" + buildApplicationAndInstancesString(applicationName, host));
    }

    /** 判断节点信息是否存在与 restartInstances*/
    public boolean hasRestartInstance(String applicationName, String host) {
        return restartInstances.contains(buildApplicationAndInstancesString(applicationName, host));
    }


    /** 当节点信息变化时会自动调用此方法*/
    @Override
    public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
        // 查询出监听器下所有的目录配置信息
        final List<String> restartInstance = zkClient.getChildren().forPath(LISTEN_PATHS);
        if(CollectionUtils.isEmpty(restartInstance)) {
            this.restartInstances = Collections.emptySet();
        }else{
            this.restartInstances = new HashSet<>(restartInstance);
        }

    }
}
